#include <QPainter>

#include "UIKeyboard.h"
#include "UITouch.h"
#include "UIFont.h"

// ===========================================================================
//  PUBLIC Methods (Delegate)
// ===========================================================================
UIKeyboardDelegate::UIKeyboardDelegate() {
}

UIKeyboardDelegate::~UIKeyboardDelegate() {
}

void UIKeyboardDelegate::keyPressed (const QChar& key) {
    Q_UNUSED(key)
}

void UIKeyboardDelegate::returnPressed (void) {
}

void UIKeyboardDelegate::backspacePressed (void) {
}

// ===========================================================================
//  PRIVATE Class
// ===========================================================================
class UIKeyboardPrivate {
    public:
        UIKeyboardOrientation orientation;
        UIKeyboardDelegate *delegate;
        int showPopup;

    public:
        void drawVerticalKeyboard (QPainter *p);
        void drawHorizontalKeyboard (QPainter *p);

        int verticalKeyGroupByPos (const QPointF& pos);
        int horizontalKeyGroupByPos (const QPointF& pos);

        int verticalKeyByPos (const QPointF& pos);
        int horizontalKeyByPos (const QPointF& pos);

        QString groupByKey (int group);
        QChar letterByGroupKey (int group, int key);        

        void keyPressed (const QChar& key);

    private:
        void drawSmallKeyGroup (QPainter *p, int x, int y, 
                                const QString& text,
                                const QString& text2);

        void drawSpaceSymbol (QPainter *p, int x, int y);
        void drawReturnSymbol (QPainter *p, int x, int y);
        void drawBackspaceSymbol (QPainter *p, int x, int y);
};

void UIKeyboardPrivate::keyPressed (const QChar& key) {
    if (delegate == NULL)
        return;

    if (key == '\n')
        delegate->returnPressed();
    else if (key == '\b')
        delegate->backspacePressed();
    else
        delegate->keyPressed(key);
}

QString UIKeyboardPrivate::groupByKey (int group) {
    const char *letters[] = {
        "QWERqwer",
        "TYUItyui",
        "OP()op[]",
        "12345678",
        "@ASD#asd",
        "FGHJfghj",
        "KL{}kl'^",
        "90.=+-*/",
        "<ZXC>zxc",
        "VBNMvbnm",
        "|\\!\"$%&?",
        "_,;:  \b\n"
    };
    return(letters[group]);
}

QChar UIKeyboardPrivate::letterByGroupKey (int group, int key) {
    return(groupByKey(group)[key]);
}

void UIKeyboardPrivate::drawHorizontalKeyboard (QPainter *p) {
    QLinearGradient keyboardHBg(0, 0, 0, 195);
    keyboardHBg.setColorAt(0.0f, QColor(0x91, 0x99, 0xa4));
    keyboardHBg.setColorAt(1.0f, QColor(0x4a, 0x53, 0x61));

    p->setPen(Qt::NoPen);
    p->setBrush(keyboardHBg);
    p->drawRect(0, 0, 640, 195);

    drawSmallKeyGroup(p,   2,  10, "QWER", "qwer");
    drawSmallKeyGroup(p, 109,  10, "TYUI", "tyui");
    drawSmallKeyGroup(p, 216,  10, "OP ( )", "op [ ]");
    drawSmallKeyGroup(p, 324,  10, "VBNM", "vbnm");
    drawSmallKeyGroup(p, 431, 10, "1234", "5678");
    drawSmallKeyGroup(p, 538, 10, "| \\ ! \"", "$ % & ?");

    drawSmallKeyGroup(p,   2, 105, "@ ASD", "# asd");
    drawSmallKeyGroup(p, 109, 105, "FGHJ", "fghj");
    drawSmallKeyGroup(p, 216, 105, "KL { }", "kl ' ^");
    drawSmallKeyGroup(p, 324, 105, "< ZXC", "> zxc");
    drawSmallKeyGroup(p, 431, 105, "9 0 . =", "+ - * /");
    drawSmallKeyGroup(p, 538, 105, "_ , ; :", "  \b\n");

    if (showPopup != -1) {
        QString keys =  groupByKey(showPopup);

        QLinearGradient kbHPopupBg(0, 4, 0, 190);
        kbHPopupBg.setColorAt(0.0f, QColor(0x22, 0x23, 0x21, 250));
        kbHPopupBg.setColorAt(1.0f, QColor(0x28, 0x28, 0x2b, 250));

        p->setBrush(kbHPopupBg);
        p->setPen(Qt::NoPen);
        p->drawRoundedRect( 120,  4, 400, 186, 12, 12);

        p->setPen(QPen(QColor(0x50, 0x50, 0x50), 1));
        p->drawLine(120, 97, 520, 100);
        p->drawLine(220,  4, 220, 186);
        p->drawLine(320,  4, 320, 186);
        p->drawLine(420,  4, 420, 186);

        p->setPen(Qt::white);
        p->setFont(UIFontBigBold(p->font()));
        p->drawText(120,  0, 100, 93, Qt::AlignCenter, QString(keys[0]));
        p->drawText(220,  0, 100, 93, Qt::AlignCenter, QString(keys[1]));
        p->drawText(320,  0, 100, 93, Qt::AlignCenter, QString(keys[2]));
        p->drawText(420,  0, 100, 93, Qt::AlignCenter, QString(keys[3]));
        p->drawText(120, 97, 100, 93, Qt::AlignCenter, QString(keys[4]));

        if (keys[5] == ' ')
            drawSpaceSymbol(p, 220 + 43, 100 + 43);
        else
            p->drawText(220, 97, 100, 93, Qt::AlignCenter, QString(keys[5]));

        if (keys[6] == '\b')
            drawBackspaceSymbol(p, 320 + 43, 100 + 43);
        else
            p->drawText(320, 97, 100, 93, Qt::AlignCenter, QString(keys[6]));

        if (keys[7] == '\n')
            drawReturnSymbol(p, 420 + 43, 100 + 43);
        else
            p->drawText(420, 97, 100, 93, Qt::AlignCenter, QString(keys[7]));
    }
}

void UIKeyboardPrivate::drawVerticalKeyboard (QPainter *p) {
    QLinearGradient keyboardBg(0, 0, 0, 295);
    keyboardBg.setColorAt(0.0f, QColor(0x91, 0x99, 0xa4));
    keyboardBg.setColorAt(1.0f, QColor(0x4a, 0x53, 0x61));

    p->setPen(Qt::NoPen);
    p->setBrush(keyboardBg);
    p->drawRect(0, 0, 480, 295);

    drawSmallKeyGroup(p,  10,  10, "QWER", "qwer");
    drawSmallKeyGroup(p, 130,  10, "TYUI", "tyui");
    drawSmallKeyGroup(p, 250,  10, "OP ( )", "op [ ]");
    drawSmallKeyGroup(p, 370,  10, "1234", "5678");

    drawSmallKeyGroup(p,  10, 105, "@ ASD", "# asd");
    drawSmallKeyGroup(p, 130, 105, "FGHJ", "fghj");
    drawSmallKeyGroup(p, 250, 105, "KL { }", "kl ' ^");
    drawSmallKeyGroup(p, 370, 105, "9 0 . =", "+ - * /");

    drawSmallKeyGroup(p,  10, 200, "< ZXC", "> zxc");
    drawSmallKeyGroup(p, 130, 200, "VBNM", "vbnm");
    drawSmallKeyGroup(p, 250, 200, "| \\ ! \"", "$ % & ?");
    drawSmallKeyGroup(p, 370, 200, "_ , ; :", "  \b\n");

    if (showPopup != -1) {
        QString keys =  groupByKey(showPopup);

        QLinearGradient kbPopupBg(0, 50, 0, 250);
        kbPopupBg.setColorAt(0.0f, QColor(0x22, 0x23, 0x21, 240));
        kbPopupBg.setColorAt(1.0f, QColor(0x28, 0x28, 0x2b, 240));

        p->setBrush(kbPopupBg);
        p->setPen(QPen(QColor(0x70, 0x70, 0x70), 2));
        p->drawRect( 40,  50, 400, 200);

        p->setPen(QPen(QColor(0x50, 0x50, 0x50), 1));
        p->drawLine( 41, 150, 438, 150);
        p->drawLine(140,  50, 140, 250);
        p->drawLine(240,  50, 240, 250);
        p->drawLine(340,  50, 340, 250);

        p->setPen(Qt::white);
        p->setFont(UIFontBigBold(p->font()));
        p->drawText( 40,  50, 100, 100, Qt::AlignCenter, QString(keys[0]));
        p->drawText(140,  50, 100, 100, Qt::AlignCenter, QString(keys[1]));
        p->drawText(240,  50, 100, 100, Qt::AlignCenter, QString(keys[2]));
        p->drawText(340,  50, 100, 100, Qt::AlignCenter, QString(keys[3]));
        p->drawText( 40, 150, 100, 100, Qt::AlignCenter, QString(keys[4]));

        if (keys[5] == ' ')
            drawSpaceSymbol(p, 140 + 43, 150 + 43);
        else
            p->drawText(140, 150, 100, 100, Qt::AlignCenter, QString(keys[5]));

        if (keys[6] == '\b')
            drawBackspaceSymbol(p, 240 + 43, 150 + 43);
        else
            p->drawText(240, 150, 100, 100, Qt::AlignCenter, QString(keys[6]));

        if (keys[7] == '\n')
            drawReturnSymbol(p, 340 + 43, 150 + 43);
        else
            p->drawText(340, 150, 100, 100, Qt::AlignCenter, QString(keys[7]));
    }
}

int UIKeyboardPrivate::verticalKeyGroupByPos (const QPointF& pos) {
    // Line 1
    if (QRectF(10, 10, 100, 80).contains(pos))
        return(0);

    if (QRectF(130, 10, 100, 80).contains(pos))
        return(1);

    if (QRectF(250, 10, 100, 80).contains(pos))
        return(2);

    if (QRectF(370, 10, 100, 80).contains(pos))
        return(3);

    // Line 2
    if (QRectF(10, 105, 100, 80).contains(pos))
        return(4);

    if (QRectF(130, 105, 100, 80).contains(pos))
        return(5);

    if (QRectF(250, 105, 100, 80).contains(pos))
        return(6);

    if (QRectF(370, 105, 100, 80).contains(pos))
        return(7);

    // Line 3
    if (QRectF(10, 200, 100, 80).contains(pos))
        return(8);

    if (QRectF(130, 200, 100, 80).contains(pos))
        return(9);

    if (QRectF(250, 200, 100, 80).contains(pos))
        return(10);

    if (QRectF(370, 200, 100, 80).contains(pos))
        return(11);

    return(-1);
}

int UIKeyboardPrivate::horizontalKeyGroupByPos (const QPointF& pos) {
    // Line 1
    if (QRectF(2, 10, 100, 80).contains(pos))
        return(0);

    if (QRectF(109, 10, 100, 80).contains(pos))
        return(1);

    if (QRectF(216, 10, 100, 80).contains(pos))
        return(2);

    if (QRectF(324, 10, 100, 80).contains(pos))
        return(9);

    if (QRectF(431, 10, 100, 80).contains(pos))
        return(3);

    if (QRectF(538, 10, 100, 80).contains(pos))
        return(10);

    // Line 2
    if (QRectF(2, 105, 100, 80).contains(pos))
        return(4);

    if (QRectF(109, 105, 100, 80).contains(pos))
        return(5);

    if (QRectF(216, 105, 100, 80).contains(pos))
        return(6);

    if (QRectF(324, 105, 100, 80).contains(pos))
        return(8);

    if (QRectF(431, 105, 100, 80).contains(pos))
        return(7);

    if (QRectF(538, 105, 100, 80).contains(pos))
        return(11);

    return(-1);
}

int UIKeyboardPrivate::verticalKeyByPos (const QPointF& pos) {
    // Line 1
    if (QRectF( 40,  50, 100, 100).contains(pos))
        return(0);

    if (QRectF(140,  50, 100, 100).contains(pos))
        return(1);

    if (QRectF(240,  50, 100, 100).contains(pos))
        return(2);

    if (QRectF(340,  50, 100, 100).contains(pos))
        return(3);

    // Line 2
    if (QRectF( 40, 150, 100, 100).contains(pos))
        return(4);

    if (QRectF(140, 150, 100, 100).contains(pos))
        return(5);

    if (QRectF(240, 150, 100, 100).contains(pos))
        return(6);

    if (QRectF(340, 150, 100, 100).contains(pos))
        return(7);

    return(-1);
}

int UIKeyboardPrivate::horizontalKeyByPos (const QPointF& pos) {
    // Line 1
    if (QRectF(120,  0, 100, 93).contains(pos))
        return(0);

    if (QRectF(220,  0, 100, 93).contains(pos))
        return(1);

    if (QRectF(320,  0, 100, 93).contains(pos))
        return(2);

    if (QRectF(420,  0, 100, 93).contains(pos))
        return(3);

    // Line 2
    if (QRectF(120, 97, 100, 93).contains(pos))
        return(4);

    if (QRectF(220, 97, 100, 93).contains(pos))
        return(5);

    if (QRectF(320, 97, 100, 93).contains(pos))
        return(6);

    if (QRectF(420, 97, 100, 93).contains(pos))
        return(7);

    return(-1);
}

void UIKeyboardPrivate::drawSmallKeyGroup (QPainter *p, int x, int y, 
                                           const QString& text,
                                           const QString& text2)
{
    p->save();

    p->setPen(Qt::NoPen);
    p->setBrush(QColor(0x44, 0x44, 0x44));
    p->drawRoundedRect(x + 3, y + 4, 100, 80, 8, 8);

    p->setBrush(QColor(0xEF, 0xEF, 0xEF));
    p->drawRoundedRect(x, y, 100, 80, 8, 8);

    p->setPen(Qt::black);
    p->setFont(UIFontSmallBold(p->font()));
    p->drawText(x, y, 100, 40, Qt::AlignHCenter | Qt::AlignBottom, text);

    if (text2 == "  \b\n") {
        // Draw Space
        x += 20; y += 50;
        drawSpaceSymbol(p, x, y);
        
        // Draw BackSpace
        x += 22; y += 5;
        drawBackspaceSymbol(p, x, y);

        // Draw Return
        x += 22;
        drawReturnSymbol(p, x, y);
    } else {
        p->drawText(x, y + 40, 100, 40, Qt::AlignHCenter | Qt::AlignTop, text2);
    }

    p->restore();
}

void UIKeyboardPrivate::drawSpaceSymbol (QPainter *p, int x, int y) {
    p->drawLine(x, y, x, y + 5);
    p->drawLine(x + 15, y, x + 15, y + 5);
    p->drawLine(x, y + 5, x + 15, y + 5);
}

void UIKeyboardPrivate::drawReturnSymbol (QPainter *p, int x, int y) {
    p->drawLine(x, y, x + 5, y - 4);
    p->drawLine(x, y, x + 5, y + 4);
    p->drawLine(x + 1, y, x + 15, y);
    p->drawLine(x + 15, y, x + 15, y - 10);
}

void UIKeyboardPrivate::drawBackspaceSymbol (QPainter *p, int x, int y) {
    p->drawLine(x, y, x + 5, y - 5);
    p->drawLine(x, y, x + 5, y + 5);
    p->drawLine(x + 5, y - 5, x + 15, y - 5);
    p->drawLine(x + 5, y + 5, x + 15, y + 5);
    p->drawLine(x + 15, y + 5, x + 15, y - 5);
    p->setFont(UIFontUltraSmallBold(p->font()));
    p->drawText(x + 4, y - 5, 10, 10, Qt::AlignCenter, "X");
}

UIKeyboard::UIKeyboard (QGraphicsItem *parent)
    : QObject(), UIView(parent), d(new UIKeyboardPrivate)
{
    d->orientation = UIKeyboardOrientationVertical;
    d->delegate = NULL;
    d->showPopup = -1;
}

UIKeyboard::~UIKeyboard() {
    if (d->delegate != NULL)
        delete d->delegate;
    delete d;
}

UIKeyboardDelegate *UIKeyboard::delegate (void) const {
    return(d->delegate);
}

void UIKeyboard::setDelegate (UIKeyboardDelegate *delegate) {
    d->delegate = delegate;
}

UIKeyboardOrientation UIKeyboard::orientation (void) const {
    return(d->orientation);
}

void UIKeyboard::setOrientation (UIKeyboardOrientation orientation) {
    d->orientation = orientation;

    switch (d->orientation) {
        case UIKeyboardOrientationVertical:
            setBoundingRect(QRectF(0.0f, 0.0f, 480.0, 295.0));
            break;
        case UIKeyboardOrientationHorizontal:
            setBoundingRect(QRectF(0.0f, 0.0f, 640.0, 195.0));
            break;
        default:
            qDebug("UIKeyboard: Invalid Orientation.");
            break;
    }
}

void UIKeyboard::drawRect (QPainter *painter, const QRect& rect) {
    Q_UNUSED(rect)

    switch (d->orientation) {
        case UIKeyboardOrientationVertical:
            d->drawVerticalKeyboard(painter);
            break;
        case UIKeyboardOrientationHorizontal:
            d->drawHorizontalKeyboard(painter);
            break;
        default:
            qDebug("UIKeyboard: Invalid Orientation.");
            break;
    }
}

void UIKeyboard::singleTapEvent (UITouch *touch) {
    QPointF tapLocation = mapFromScene(touch->currentPos());
    int key = -1;

    switch (d->orientation) {
        case UIKeyboardOrientationVertical:
            if (d->showPopup != -1)
                key = d->verticalKeyByPos(tapLocation);
            else
                key = d->verticalKeyGroupByPos(tapLocation);  
            break;
        case UIKeyboardOrientationHorizontal:
            if (d->showPopup != -1)
                key = d->horizontalKeyByPos(tapLocation);
            else
                key = d->horizontalKeyGroupByPos(tapLocation);
            break;
        default:
            qDebug("UIKeyboard: Invalid Orientation.");
            break;
    }

    if (key != -1) {
        if (d->showPopup == -1) {
            d->showPopup = key;
        } else {
            QChar letter = d->letterByGroupKey(d->showPopup, key);
            d->keyPressed(letter);
            d->showPopup = -1;
        }
        update();
    }
}

void UIKeyboard::touchHeldEvent (UITouch *touch) {
    Q_UNUSED(touch)

    if (d->showPopup != -1) {
        d->showPopup = -1;
        update();
    }
}

